﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;

using ERPStore.Offers.Repositories;
using ERPStore.Web.Html;
using ERPStore.Extensions;
using ERPStore.Web.Routing;

using CloudSoft.Extensions;
using System.Threading.Tasks;

namespace ERPStore.Offers.Controllers
{
	public class OffersController : ERPStore.Web.Controllers.StoreController
	{
		private static object m_lock = new object();

		public OffersController(
			ERPStore.Services.ICatalogService catalogService
			, ERPStore.Services.ISalesService salesService
			, Services.OffersService offerService
			, ERPStore.Services.ICacheService cacheService)
		{
			this.CatalogService = catalogService;
			this.SalesService = salesService;
			this.OfferService = offerService;
			this.CacheService = cacheService;
		}

		protected ERPStore.Services.ICatalogService CatalogService { get; private set; }
		protected ERPStore.Services.ISalesService SalesService { get; private set; }
		protected Services.OffersService OfferService { get; private set; }
		protected ERPStore.Services.ICacheService CacheService { get; private set; }

		[ERPStore.Web.Controllers.ActionFilters.TrackerActionFilter]
		public async Task<ActionResult> Offer(string offerLink)
		{
			var offer = OfferService.GetOfferByLink(offerLink) as Models.OfferEx;
			if (offer == null)
			{
				return RedirectToERPStoreRoute(ERPStore.Web.Routing.ERPStoreRoutes.HOME);
			}

			var pageId = GetPageId();
			var pageSize = 40;
			int count = 0;
			string categoryCode = Request["category"];
			string brandName = Request["brand"];

			int trycount = 1;
			IList<ERPStore.Models.Product> pagedList = null;
			while (true)
			{
				pagedList = await Task.Run<IList<ERPStore.Models.Product>>(() =>
					{
						return OfferService.GetProductList(offer, pageId, pageSize, categoryCode, brandName, out count);
					});

				if (pagedList.Count == 0)
				{
					if (trycount == 1)
					{
						trycount++;
						pageId = 0;
						categoryCode = null;
						brandName = null;
						continue;
					}
					var url = Url.RouteERPStoreUrl(ERPStore.Web.Routing.ERPStoreRoutes.HOME).AddParameter("from", "emptyoffer");
					return RedirectPermanent(url);
				}
				else
				{
					break;
				}
			}

			foreach (var item in pagedList)
			{
				OfferService.ApplyOffers(item, User.CurrentUser);
			}

			var result = new ERPStore.Models.ProductList(pagedList);
			result.ItemCount = count;
			result.PageIndex = pageId + 1;
			result.PageSize = pageSize;
			result.ListType = ERPStore.Models.ProductListType.Offer;
			if (categoryCode != null)
			{
				result.Category = CatalogService.GetCategoryByCode(categoryCode);
			}
			ViewData.Model = result;
			ViewBag.Offer = offer;

			await EventPublisherService.PublishAsync(new Web.Events.ProductListEvent(User, result, ERPStore.Models.ProductListType.Selection));

			return View(offer.ViewName);
		}

		[ERPStore.Web.Controllers.ActionFilters.TrackerActionFilter]
		public ActionResult Product(string code, string productLink)
		{
			var product = CatalogService.GetProductByCode(code);
			if (product == null)
			{
				return RedirectToERPStoreRoute(ERPStore.Web.Routing.ERPStoreRoutes.HOME);
			}

			var offer = OfferService.AdminOffersService.GetOfferByProduct(product);
			if (offer == null)
			{
				return RedirectPermanent(Url.Href(product));
			}
			OfferService.ApplyOffers(product, User.CurrentUser);
			ViewData.Model = product;
			ViewBag.Offer = offer;
			if (!offer.ProductViewName.IsNullOrTrimmedEmpty())
			{
				return View(offer.ProductViewName);
			}
			return View();
		}

		public string GetOfferHref(string offerCode)
		{
			string routeName = null;
			var offerId = System.Text.RegularExpressions.Regex.Replace(offerCode, @"\D+", "");
			var id = 0;
			int.TryParse(offerId, out id);
			routeName = string.Format("OfferLink.{0}", id);
			return Url.RouteERPStoreUrl(routeName);
		}

		#region Partial Views

		public ActionResult ShowBrandList(int offerId, string viewName)
		{
			var key = string.Format("Offer:ProductList:{0}", offerId);
			var productList = CacheService[key] as IList<ERPStore.Models.Product>;
			if (productList == null)
			{
				return new EmptyResult();
			}

			var brandIdList = productList.Where(i => i.Brand != null)
									.GroupBy(i => i.Brand.Id)
									.ToList();

			var result = CatalogService.GetBrands().ToClonedList();
			foreach (var brand in result)
			{
				brand.IsSelected = false;
			}
			
			foreach (var brandGroup in brandIdList)
			{
				int brandId = brandGroup.Key;
				int count = brandGroup.Count();

				var brand = result.First(i => i.Id == brandId);
				if (brand != null)
				{
					brand.ProductCount = count;
					brand.IsSelected = true;
				}
			}

			result.RemoveAll(i => i.IsSelected == false);

			ViewData.Model = result;
			return PartialView(viewName);
		}

		public ActionResult ShowProductCategoryList(int offerId, string viewName)
		{
			var key = string.Format("Offer:ProductList:{0}", offerId);
			var productList = CacheService[key] as IList<ERPStore.Models.Product>;
			if (productList == null)
			{
				return new EmptyResult();
			}

			var categoryIdList = productList.Where(i => i.Category != null)
									.GroupBy(i => i.Category.Id)
									.ToList();

			var result = CatalogService.GetCategories().ToClonedList();

			// Mise à jour du nombre de produits à 0
			result.Traverse(i => { i.ProductCount = 0; i.IsSelected = false; });

			// Creation de la liste de resultat
			foreach (var categoryGroup in categoryIdList)
			{
				int categoryId = categoryGroup.Key;
				int c = categoryGroup.Count();
				var category = result.DeepFirst(i => i.Id == categoryId);
				if (category != null)
				{
					category.ProductCount = c;
					// Selection jusqu'a la categorie root
					result.ActionToRoot(category, i => { i.IsSelected = true; });
				}
			}

			result.DeepRemoveAll(i => !i.IsSelected || i.DeepProductCount == 0);

			// CacheService.Add(key, result, DateTime.Now.AddHours(1));
			ViewData.Model = result;
			return PartialView(viewName);
		}

		public ActionResult ShowProductListView(string offerCode, string viewName, int productCount, List<ERPStore.Models.SortProperty> sort = null)
		{
			var offer = GetOfferByCode(offerCode);

			return ShowOffers(offer, viewName, productCount);
		}

		public ActionResult ShowOffersByProductCategoryView(string offerTag, int productCategoryId, string viewName, int? productCount)
		{
			var offer = OfferService.AdminOffersService.GetCurrentOffers()
							.Where(i => i.Category == offerTag 
								&& i.ProductCategoryId == productCategoryId)
							.FirstOrDefault();

			if (offer == null
				|| offer.ProductList == null)
			{
				return new EmptyResult();
			}

			return ShowOffers(offer, viewName, productCount);
		}

		public ActionResult ShowOffersByBrandView(string offerTag, int brandId, string viewName, int? productCount)
		{
			var offer = OfferService.AdminOffersService.GetCurrentOffers()
							.Where(i => i.Category == offerTag
								&& i.BrandId == brandId)
							.FirstOrDefault();

			if (offer == null
				|| offer.ProductList == null)
			{
				return new EmptyResult();
			}

			return ShowOffers(offer, viewName, productCount);
		}

		public ActionResult ShowOffers(Models.OfferEx offer, string viewName, int? productCount)
		{
			var productIdList = offer.ProductList.OrderBy(i => i.OrderIndex.GetValueOrDefault(i.Id)).Select(i => new { ProductId = i.ProductId, OrderIndex = i.OrderIndex.GetValueOrDefault(i.Id) }).Distinct();
			if (productCount.HasValue)
			{
				productIdList = productIdList.Take(productCount.Value);
			}
			var productList = CatalogService.GetProductListByIdList(productIdList.Select(i => i.ProductId), true);
			foreach (var product in productList)
			{
				var orderIndex = productIdList.Where(i => i.ProductId == product.Id).FirstOrDefault().OrderIndex;
				var currentUser = User.CurrentUser;
				OfferService.ApplyOffers(product, currentUser);
				product.Tag = orderIndex;
			}

			ViewBag.Offer = offer;
			ViewData.Model = productList.OrderBy(i => (int)i.Tag);

			return PartialView(viewName);
		}

		public ActionResult ShowContinuousProductList(int offerId, int pageIndex, string categoryCode, string brandName, string viewName)
		{
			var offer = OfferService.GetOfferById(offerId);
			int count = 0;
			var pagedList = OfferService.GetProductList(offer, pageIndex, 40, categoryCode, brandName, out count);

			foreach (var item in pagedList)
			{
				OfferService.ApplyOffers(item, User.CurrentUser);
			}

			var result = new ERPStore.Models.ProductList(pagedList);
			result.ItemCount = count;
			result.PageIndex = pageIndex;
			result.PageSize = 40;
			result.ListType = ERPStore.Models.ProductListType.Offer;
			ViewData.Model = result;
			ViewBag.Offer = offer;

			return PartialView(viewName);
		}

		#endregion

		private Models.OfferEx GetOfferByCode(string offerCode)
		{
			Models.OfferEx offer = null;
			var offerId = System.Text.RegularExpressions.Regex.Replace(offerCode, @"\D+", "");
			var id = 0;
			if (int.TryParse(offerId, out id))
			{
				try
				{
					offer = OfferService.GetOfferById(id);
				}
				catch
				{
					Logger.Warn("Offer with id {0} does not exists", offerId);
				}
			}
			if (offer == null
				|| offer.ProductList == null)
			{
				offer = new Models.OfferEx();
				offer.ProductList = new List<Models.OfferedProduct>();
			}
			return offer;
		}


	}
}
